import socket
import sys
import time


def send_request(host, port, request, max_retries=3):

    for attempt in range(max_retries):
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.settimeout(5.0)  # 设置5秒超时
                s.connect((host, port))
                s.sendall(request.encode())
                response = s.recv(1024).decode().strip()
                return response
        except (socket.timeout, ConnectionRefusedError) as e:
            if attempt == max_retries - 1:
                raise ConnectionError(f"Failed after {max_retries} retries: {str(e)}")
            print(f"Attempt {attempt + 1} failed, retrying... ({str(e)})")
            time.sleep(1)  # 每次重试间隔1秒


def validate_request(line):
    """
    验证请求行的格式和长度是否符合协议要求
    Args:
        line (str): 输入文件中的单行请求（如 'PUT key1 value1'）
    Returns:
        bool: 是否有效
    """
    parts = line.split()
    if len(parts) < 2:
        print(f"Invalid format: '{line}' (missing arguments)")
        return False

    op = parts[0]
    if op not in ('PUT', 'GET', 'READ'):
        print(f"Invalid operation: '{op}' in line '{line}'")
        return False

        # 检查键值长度限制（协议要求总长≤970字符）
        key_value = ' '.join(parts[1:])
        if len(key_value) > 970:
            print(f"Key-value too long (max 970 chars): '{key_value[:50]}...'")
            return False

        # PUT操作需要值参数
        if op == 'PUT' and len(parts) < 3:
            print(f"PUT operation missing value: '{line}'")
            return False

        return True

    def format_request(line):
        """
        将输入行转换为协议要求的格式（如 '012 P key1 value1'）
        Args:
            line (str): 有效的请求行（已通过validate_request检查）
        Returns:
            str: 格式化后的协议字符串
        """
        parts = line.split()
        op = parts[0]
        key = parts[1]

        if op == 'PUT':
            value = ' '.join(parts[2:])
            request_content = f"P {key} {value}"
        else:  # GET 或 READ
            request_content = f"{'G' if op == 'GET' else 'R'} {key}"

        # 计算总长度（NNN占3位 + 空格 + 内容长度）
        total_len = len(request_content) + 4
        return f"{total_len:03d} {request_content}"

    def process_file(host, port, filename):
        """
        处理请求文件并发送到服务器
        Args:
            host (str): 服务器地址
            port (int): 服务器端口
            filename (str): 请求文件路径
        """
        try:
            with open(filename, 'r') as file:
                for line_num, line in enumerate(file, 1):
                    line = line.strip()
                    if not line:
                        continue

                    print(f"[Line {line_num}] Processing: {line}")

                    if not validate_request(line):
                        continue

                    request = format_request(line)
                    try:
                        response = send_request(host, port, request)
                        print(f"Response: {response}")
                    except ConnectionError as e:
                        print(f"Fatal error at line {line_num}: {str(e)}")
                        break

                    time.sleep(0.1)  # 避免高频请求导致端口占用
        except FileNotFoundError:
            print(f"Error: File '{filename}' not found")
        except Exception as e:
            print(f"Unexpected error: {str(e)}")

    if __name__ == "__main__":
        if len(sys.argv) != 4:
            print("Usage: python client.py <hostname> <port> <request_file>")
            print("Example: python client.py localhost 51234 requests.txt")
            sys.exit(1)

        try:
            host = sys.argv[1]
            port = int(sys.argv[2])
            filename = sys.argv[3]

            # 验证端口范围（50000-59999）
            if not (50000 <= port <= 59999):
                raise ValueError("Port must be between 50000 and 59999")

            process_file(host, port, filename)
        except ValueError as e:
            print(f"Invalid argument: {str(e)}")
            sys.exit(1)